#pragma once

#include "HSViewApi.h"
#include <memory>

class Menu;
namespace Ogre
  {
  struct FrameEvent;
  class  OverlaySystem;
  class FrameListener;
  class OgreFramework;
  class OverlaySystem;
  }
class InputManager;
class MonkeyScene;
class World;
class Model3DStorage;
class SceneController;
class WorldUpdater;
class Picker;
class EventHandler;

class GameController;

template<class T>
class TimerManager;

class Menu;
struct Ogre::FrameEvent;
namespace Ogre
  {
  class OverlaySystem;
  }

class Application : public  Ogre::FrameListener
  {
  public:
    HSVIEW_API Application();
    HSVIEW_API ~Application();
    HSVIEW_API void Start();
    HSVIEW_API void Shutdown();

    HSVIEW_API OgreFramework& GetOgre() const;
    HSVIEW_API World& GetWorld() const;
    HSVIEW_API SceneController& GetSceneController() const;
    HSVIEW_API WorldUpdater& GetWorldUpdater() const;
    HSVIEW_API GameController& GetGameController() const;
    HSVIEW_API const Model3DStorage& GetModelStorage() const;
    HSVIEW_API Picker& GetPicker() const;
		HSVIEW_API void ResetPicker();

    HSVIEW_API bool IsEventHandler(const std::string &i_handler_name) const;
    HSVIEW_API const Menu& GetMenu() const;

    HSVIEW_API void ResetHandler();
    HSVIEW_API void ResetHandler(std::shared_ptr<EventHandler> i_handler);
    HSVIEW_API void RaiseClickEvent(const OIS::MouseEvent &evt, OIS::MouseButtonID id);
    HSVIEW_API void RaiseMouseUpEvent(const OIS::MouseEvent &evt, OIS::MouseButtonID id);
    HSVIEW_API void RaiseMoveEvent(const OIS::MouseEvent &evt);
    
  protected:
    virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt) override;

  private:
    void _InitModel3DStorage();
    void _InitGame();
    void _CreateInitialScene();

  private:
    bool m_shutdown;
    std::unique_ptr<OgreFramework> mp_ogre;
    std::unique_ptr<InputManager> mp_input_manager;
    std::unique_ptr<Model3DStorage> mp_model_storage;
    std::shared_ptr<MonkeyScene> mp_monkey_scene;
    std::shared_ptr<Ogre::OverlaySystem> mp_overlay;
    std::shared_ptr<Menu> mp_menu;

    std::unique_ptr<SceneController> mp_scene_controller;
    std::unique_ptr<WorldUpdater> mp_world_updater;
    std::unique_ptr<World> mp_world;
    std::unique_ptr<Picker> mp_picker;
    
    std::unique_ptr<GameController> mp_game_controller;

    std::unique_ptr<CEGUIFramework> mp_cegui_framework;

    std::shared_ptr<EventHandler> mp_event_handler;
    std::shared_ptr<TimerManager<WorldUpdater>> mp_timer_manager;
  };